/**
 *  EKology - An Ecosystem Simulation Framework
 *  Copyright (C) 2008  Aarón Tavío - aaron.tavio at gmail.com - ULPGC
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package fungusEater.ekosystem;


import fungusEater.*;
import fungusEater.datatypes.*;

import net.ekology.ekosystem.*;
import net.ekology.ekosystem.datatypes.*;
import net.ekology.core.datatypes.*;

import java.awt.*;
import java.awt.geom.*;
import java.util.Hashtable;


/**
 * @author Aarón Tavío - aaron.tavio at gmail.com
 * @version 1.0.0 - 20081019-1700
 */
public class Factory extends AbioticAgent {
    private Taros oTaros;
    
    private Hashtable<OreType,Double> htAsset;
    private Hashtable<OreType,Double> htNeed;
    private int iMinCommunitySize;
    private OreType oCollectingOre;
    private CommunityStats oCommunityStats;
    private int iTimeBuilding;
    
    
    
    ///////////////////////////////////
    // Initialization methods
    ///////////////////////////////////
    public Factory() {
        htAsset = new Hashtable<OreType,Double>();
        htAsset.put(OreType.A_TYPE,0.0);
        htAsset.put(OreType.B_TYPE,0.0);
        htAsset.put(OreType.C_TYPE,0.0);
        
        htNeed = new Hashtable<OreType,Double>();
        htNeed.put(OreType.A_TYPE,100.0);
        htNeed.put(OreType.B_TYPE,100.0);
        htNeed.put(OreType.C_TYPE,100.0);
        
        iTimeBuilding = 0;
        iMinCommunitySize = Config.FA_COMMUNITY_SIZE;
        selectCollectingOreType();
        oCommunityStats = new CommunityStats();
    }
    
    
    @Override
    public void initialize() {
        System.out.printf("Factory.java->initialize();\n"); // DEBUG
        oTaros = (Taros) super.oBiotope; // This is neccesary to access Taros' specific methods
        
        setID(FungusEaterHelper.generateID());
        
        setPosition(new EKVector(0,0));
        setOrientation(new EKVector(0,1));
    }
    
    
    ///////////////////////////////////
    // Automaton control methods
    ///////////////////////////////////
    @Override
    public int _DO(String sCurrentStateName, int iEKTimeSlice) {
        int iEKTimeUsed;
        System.out.printf("Factory.java->_DO(\"%s\");\n",sCurrentStateName); // DEBUG

        iEKTimeUsed = (Integer) super._DO(sCurrentStateName,iEKTimeSlice);
        printState(); // DEBUG
        
        return iEKTimeUsed;
    }
    
   
    public int buildingCollector_DO(int iEKTimeSlice) {
        int iEKTimeUsed;
        
        iTimeBuilding += iEKTimeSlice;
        if (iTimeBuilding >= Config.FA_AGENT_BUILD_TIME) {
            
            buildCollector();
            
            iEKTimeUsed = iEKTimeSlice - (iTimeBuilding - Config.FA_AGENT_BUILD_TIME);
            iTimeBuilding = 0;
        } else iEKTimeUsed = iEKTimeSlice;
        
        return iEKTimeUsed;
    }
    
    
    public int fewCollectors_DO(int iEKTimeSlice) {
        int iEKTimeUsed;
        
        if (!enoughOreToBuild()) iEKTimeUsed = iEKTimeSlice;
        else iEKTimeUsed = 0;
            
        return iEKTimeUsed;
    }
    
    
    
    ///////////////////////////////////
    // Overriden methods
    ///////////////////////////////////
    @Override
    public String[] getAttributeNames() {
        String[] aResult = {"htAsset","htNeed", "iMinCommunitySize", "oCollectingOre"};
 
        return aResult;
    }
    
    
    @Override
    public Attribute getAttribute(String sName) {
        Attribute oResult = null;
        
        if (sName.equals("htAsset")) oResult = new Attribute<String>("htAsset",htAsset.toString());
        else if (sName.equals("htNeed")) oResult = new Attribute<String>("htNeed",htNeed.toString());
        else if (sName.equals("iMinCommunitySize")) oResult = new Attribute<Integer>("iMinCommunitySize",iMinCommunitySize);
        else if (sName.equals("oCollectingOre")) oResult = new Attribute<OreType>("oCollectingOre",oCollectingOre);
        
        return oResult;
    }
    
    
    @Override
    public void setAttribute(String sName, String sValue) {
        if (sName.equals("iMinCommunitySize")) iMinCommunitySize = Integer.parseInt(sValue);
        else if (sName.equals("oCollectingOre")) oCollectingOre = OreType.valueOf(sValue.toUpperCase());
    }  
    
    
    public void draw(Graphics2D g2) {
        Rectangle2D.Double oRectangle;
        
        oRectangle = new Rectangle2D.Double(-35,-25, 70, 50);
        g2.setStroke(new BasicStroke(2f));
        g2.setColor(new Color(0.5f,0.5f,0.5f));
        g2.draw(oRectangle);
        g2.setColor(new Color(0.4f,0.4f,0.4f));
        g2.fill(oRectangle);
        
        Ellipse2D.Double oChimney1;
        oChimney1 = new Ellipse2D.Double(25,-20,5,5);
        g2.setStroke(new BasicStroke(1f));
        g2.setColor(new Color(0.3f,0.3f,0.3f));
        g2.draw(oChimney1);
        g2.setColor(Color.WHITE);
        g2.fill(oChimney1);
        
        Ellipse2D.Double oChimney2;
        oChimney2 = new Ellipse2D.Double(18,-20,5,5);
        g2.setColor(new Color(0.3f,0.3f,0.3f));
        g2.draw(oChimney2);
        g2.setColor(Color.WHITE);
        g2.fill(oChimney2);
        
        Ellipse2D.Double oChimney3;
        oChimney3 = new Ellipse2D.Double(11,-20,5,5);
        g2.setColor(new Color(0.3f,0.3f,0.3f));
        g2.draw(oChimney3);
        g2.setColor(Color.WHITE);
        g2.fill(oChimney3);
    }
    
    
    
    ///////////////////////////////////
    // Other methods
    ///////////////////////////////////        
    
    
    private void printState() {
        System.out.printf("Factory=[htAsset:%s; - htNeed:%s; - iCommunitySize: '%d'; - iMinCommunitySize: '%d', oCollectingOre:%s;]\n",htAsset.toString(),htNeed.toString(),this.oCommunityStats.getCommunitySize(),iMinCommunitySize, oCollectingOre.toString());
    }
    
    
    public void unloadOre(FungusEater oFungusCollector, OreType oType, double dAmount) {
        if (!oCommunityStats.contains(oFungusCollector.getID())) oCommunityStats.addCollector(oFungusCollector.getID(), oFungusCollector.getGenome());
        oCommunityStats.addOreCollected(oFungusCollector.getID(), dAmount);
        
        htAsset.put(oType, htAsset.get(oType) + dAmount);
        selectCollectingOreType();
        oFungusCollector.setCollectingOre(oCollectingOre);
    }
    
    
    public int getMinCommunitySize() {
        return iMinCommunitySize;
    }
    
    
    public boolean enoughOre() {
        boolean bResult;
        
        bResult = true;
        for(OreType oType: OreType.values()) {
            if (htAsset.get(oType) < htNeed.get(oType)) {
                bResult = false;
                break;
            }
        }
        
        return bResult;
    }
    
    
    public boolean enoughOreToBuild() {
        return (htAsset.get(OreType.A_TYPE) >= Config.FA_ORE_NEEDED_TO_BUILD);
    }
    
    
    /**
     * Selects the first available oretype to collect
     * 
     * @return
     */
    private void selectCollectingOreType() {
        for(OreType oType: OreType.values()) {
            oCollectingOre = oType;
            if (htAsset.get(oType)<htNeed.get(oType)) break;
        }
    }
    
    
    private void buildCollector() {
        double dOreAmount;
        Genome oNewGenome;
        Genome[] aBestGenomes;
        FungusEater oFungusEater;
        
        System.out.printf("Factory.java->buildCollector()\n");
        
        dOreAmount = htAsset.get(Config.FA_ORETYPE_TO_BUILD);
        if (dOreAmount >= Config.FA_ORE_NEEDED_TO_BUILD) {
            aBestGenomes = oCommunityStats.getBestGenomes(2);
            
            if (aBestGenomes.length > 1) oNewGenome = GeneticOperators.crossover(aBestGenomes[0], aBestGenomes[1]);
            else oNewGenome = aBestGenomes[0];
            
            GeneticOperators.mutation(oNewGenome,Config.FE_FEATURE_MUTATION_PROBABILITY);
            
            oFungusEater = new FungusEater(FungusEaterHelper.generateID(),oTaros,oNewGenome);
            oTaros.fungusEaterCrated(oFungusEater);
            
            htAsset.put(Config.FA_ORETYPE_TO_BUILD, (dOreAmount - Config.FA_ORE_NEEDED_TO_BUILD));
        }
        
    }
    
    
}
